package x.ovo.wechat.bot.plugin;

import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.BufferedSource;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.JSONArray;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONUtil;
import org.jetbrains.annotations.NotNull;
import x.ovo.wechat.bot.core.Constant;
import x.ovo.wechat.bot.core.message.TextMessage;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j(topic = "AiExecutor")
@SuppressWarnings("LoggingSimilarMessage")
public class Talker {

    private static final OkHttpClient CLIENT = new OkHttpClient.Builder().readTimeout(150, TimeUnit.SECONDS).build();

    @Builder
    @RequiredArgsConstructor
    public static class Param {
        private final String id;
        private final String host;
        private final Prompt prompt;
        private final TextMessage message;
        private final List<String> tokens;
    }

    public static String talk(Param param) {
        Request request = buildRequest(param, false);
        log.debug("ai request start");
        try (Response response = CLIENT.newCall(request).execute()) {
            if (response.isSuccessful()) {
                JSONObject obj = JSONUtil.parseObj(response.body().string());
                String content = obj.getByPath("choices[0].message.content", String.class);
                String groupHead = StrUtil.format("@{} {}{}", param.message.getMember().getNickName(), param.message.getContent(), Constant.delimiter);
                param.message.getFrom().sendMessage(((!Prompt.isInner(param.prompt) && param.message.isGroup()) ? groupHead : "") + content);
                log.debug("ai request success");
                return obj.getStr("id");
            }
            log.error("请求失败，HTTP code: {}", response.code());
            String groupHead = StrUtil.format("@{} {}{}", param.message.getMember().getNickName(), param.message.getContent(), Constant.delimiter);
            param.message.getFrom().sendMessage((!Prompt.isInner(param.prompt) && param.message.isGroup() ? groupHead : "") + "请求失败，HTTP code: " + response.code());
        } catch (IOException e) {
            log.error("请求出现异常: {}", e.getMessage());
            String groupHead = StrUtil.format("@{} {}{}", param.message.getMember().getNickName(), param.message.getContent(), Constant.delimiter);
            param.message.getFrom().sendMessage((!Prompt.isInner(param.prompt) && param.message.isGroup() ? groupHead : "") + "请求出现异常: " + e.getMessage());
        }
        return null;
    }

    public static String talkStream(Param param) {
        Request request = buildRequest(param, true);
        AtomicReference<String> id = new AtomicReference<>();
        log.debug("ai request start");
        CLIENT.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                log.error("请求出现异常: {}", e.getMessage());
                String groupHead = StrUtil.format("@{} {}{}", param.message.getMember().getNickName(), param.message.getContent(), Constant.delimiter);
                param.message.getFrom().sendMessage((!Prompt.isInner(param.prompt) && param.message.isGroup() ? groupHead : "") + "请求出现异常: " + e.getMessage());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                if (!response.isSuccessful()) {
                    log.error("请求失败，HTTP code: {}", response.code());
                    String groupHead = StrUtil.format("@{} {}{}", param.message.getMember().getNickName(), param.message.getContent(), Constant.delimiter);
                    param.message.getFrom().sendMessage((!Prompt.isInner(param.prompt) && param.message.isGroup() ? groupHead : "") + "请求失败，HTTP code: " + response.code());
                    return;
                }
                StringBuilder sb = new StringBuilder();
                try (ResponseBody responseBody = response.body()) {
                    BufferedSource source = responseBody.source();
                    source.request(Long.MAX_VALUE);
                    while (!Thread.currentThread().isInterrupted()) {
                        String line = source.readUtf8Line();
                        // line为null结束循环
                        if (Objects.isNull(line)) break;
                        // 跳过空行
                        if (StrUtil.isBlank(line)) continue;
                        // sse流未结束，则解析流
                        if (!"data: [DONE]".equals(line)) {
                            // 去除多余字符串并转换为json
                            JSONObject obj = JSONUtil.parseObj(line.replace("data: ", ""));
                            id.set(obj.getStr("id"));
                            String content = obj.getByPath("choices[0].delta.content", String.class);

                            if (!content.contains("\n")) {
                                // line不包含换行符
                                sb.append(content);
                            } else {
                                // 包含换行符
                                String[] parts = content.split("\\n+", 2);
                                sb.append(parts[0]);
                                param.message.getFrom().sendMessage(sb.toString());
                                sb = new StringBuilder();
                                sb.append(parts[1]);
                            }
                        } else {
                            param.message.getFrom().sendMessage(sb.toString());
                            break; // 没有更多数据
                        }
                    }
                } catch (IOException e) {
                    log.error("请求出现异常: {}", e.getMessage());
                    String groupHead = StrUtil.format("@{} {}{}", param.message.getMember().getNickName(), param.message.getContent(), Constant.delimiter);
                    param.message.getFrom().sendMessage((!Prompt.isInner(param.prompt) && param.message.isGroup() ? groupHead : "") + "请求出现异常: " + e.getMessage());
                }
            }
        });
        return id.get();
    }

    private static @NotNull Request buildRequest(Param param, boolean stream) {
        // 如果message content以内部文件头为前缀，则上传文件并获取url
        Object content = param.message.getContent();
        if (content instanceof String c && c.startsWith("inner::file://")) {
            String filePath = StrUtil.removePrefix(c, "inner::file://");
            String upload = FileUploader.upload(FileUtil.file(filePath));
            if (Objects.nonNull(upload)) {
                JSONObject object = JSONUtil.ofObj().set("type", "file").set("file_url", JSONUtil.ofObj().set("url", upload));
                content = JSONUtil.ofArray().put(object);
            }
        }
        String url = param.host + "/v1/chat/completions";
        JSONArray array = JSONUtil.ofArray();
        if (Objects.nonNull(param.prompt) && !Prompt.NULL.equals(param.prompt)) array.put(param.prompt.getObject());
        array.put(JSONUtil.ofObj().set("role", "user").set("content", content));
        String object = JSONUtil.ofObj()
                .set("model", "gpt-4o")
                .set("conversation_id", param.id)
                .set("temperature", 0.7)
                .set("messages", array)
                .set("stream", stream)
                .toStringPretty();
        log.debug(object);
        return new Request.Builder()
                .url(url)
                .post(RequestBody.create(object, MediaType.parse("application/json")))
                .header("Authorization", "Bearer " + String.join(",", param.tokens))
                .build();
    }

}
